package com.itic.appbase.framework.interceptor;

import java.text.SimpleDateFormat;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.NamedThreadLocal;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.RequestContextUtils;

import com.itic.appbase.framework.common.controller.BaseController;
import com.itic.appbase.framework.utils.DateHelper;
import com.itic.appbase.framework.utils.ReflectHelper;
import com.itic.appbase.framework.utils.SpringContextHelper;
import com.itic.appbase.framework.utils.StringHelper;

/**
 * 日志拦截器. <br>
 * 拦截请求URI，并结合日志处理类进行日志的记录.
 * 
 * @ClassName: LogInterceptor
 * @Description: 日誌切面，攔截URI
 * @author: djp_ivan
 * @date: Apr 15, 2015 10:10:23 AM
 * @version: V1.0
 * @Update_Comments: by djp_ivan at Apr 15, 2015 - description
 */
public class LogInterceptor
        extends BaseController
        implements HandlerInterceptor {

    private static final ThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("ThreadLocal StartTime");
    private String                         clazz;
    private String                         method;

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    /**
     * 調用計時
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (LOGGER.isDebugEnabled()) {
            long beginTime = System.currentTimeMillis();// 1、开始时间
            startTimeThreadLocal.set(beginTime); // 线程绑定变量（该数据只有当前请求的线程可见）
            LOGGER.debug("开始计时: {}  URI: {}", new SimpleDateFormat("hh:mm:ss.SSS").format(beginTime),
                    request.getRequestURI());
        }
        return true;
    }

    /**
     * 返回結果頁面監聽
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView)
            throws Exception {
        if (LOGGER.isDebugEnabled()) {
            if (modelAndView != null) {
                LOGGER.info("ViewName: " + modelAndView.getViewName());
            }
        }
    }

    /**
     * 操作完成記錄
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // 获取当前执行对象
        if (StringHelper.isNoneBlank(this.getClazz()) && StringHelper.isNotBlank(this.getMethod())) {
            String beanName = this.getClazz();
            Object obj = null;
            // Spring Context
            if (!SpringContextHelper.getApplicationContext().containsBean(beanName)) {
                // Spring MVC Context
                WebApplicationContext webApplicationContext = RequestContextUtils.getWebApplicationContext(request);
                obj = webApplicationContext.getBean(this.getClazz());
            } else {
                obj = SpringContextHelper.getBean(beanName);
            }
            if (null != obj) {
                // 执行MVC中配置操作，记录日志...
                ReflectHelper.invokeMethod(obj, this.getMethod(), new Object[] { request },
                        new Class[] { HttpServletRequest.class });
            }
        }
        if (LOGGER.isDebugEnabled()) {
            long beginTime = startTimeThreadLocal.get();// 得到线程绑定的局部变量（开始时间）
            long endTime = System.currentTimeMillis(); // 2、结束时间
            LOGGER.debug("计时结束：{}  耗时：{}  URI: {}  最大内存: {}m  已分配内存: {}m  已分配内存中的剩余空间: {}m  最大可用内存: {}m",
                    new SimpleDateFormat("hh:mm:ss.SSS").format(endTime), DateHelper
                            .formatDateTime(endTime - beginTime), request.getRequestURI(), Runtime.getRuntime()
                            .maxMemory() / 1024 / 1024, Runtime.getRuntime().totalMemory() / 1024 / 1024, Runtime
                            .getRuntime().freeMemory() / 1024 / 1024, (Runtime.getRuntime().maxMemory()
                            - Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1024 / 1024);
        }

    }

}
